package com.cloudfunx.common.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.annotation.HttpConstraint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author linjiayu
 * @date 2019-08-11
 */
@Slf4j
@ControllerAdvice
public class DefaultExceptionHandle {

    @ExceptionHandler(value = TokenException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public Object tokenErrorHandle(HttpServletRequest req, HttpServletResponse resp, TokenException e) throws IOException {
        log.error("token validate error");
        log.error("tokenErrorHandle:{}", e.getMessage());
        // print(resp, HttpStatus.UNAUTHORIZED.value(), new BizResponse<>(e.getCode(), e.getMsg()));

        return new BizResponse<>(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = NoLoginException.class)
    @ResponseStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION)
    @ResponseBody
    public Object loginErrorHandle(HttpServletRequest req, HttpServletResponse resp, NoLoginException e) throws IOException {
        log.error("no login error");
        log.error("loginErrorHandle:{}", e.getMessage());
        // print(resp, HttpStatus.NON_AUTHORITATIVE_INFORMATION.value(), new BizResponse<>(e.getCode(), e.getMsg()));

        return new BizResponse<>(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public Object bizExceptionHandle(HttpServletRequest req, BizException e) {
        log.error("bizExceptionHandle:{}", e.getMessage());
        log.error("bizExceptionHandle:{}" ,getTrace(e));
        return new BizResponse<>(e.getCode(), e.getMsg());
    }

    @Deprecated
    @ExceptionHandler(value = BizPageException.class)
    public String bizExceptionHandle(Model model, HttpServletRequest req, BizPageException e) {
        log.error("bizPageException:{}", e.getMessage());
        model.addAttribute("message", e.getMessage());
        return "/errorHandle";
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Object methodArgumentNotValidExceptionHandle(HttpServletRequest req, MethodArgumentNotValidException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        String defaultMessage = fieldError.getDefaultMessage();
        if (!StringUtils.isEmpty(defaultMessage)) {
            log.error(defaultMessage);
        }
        BizResponse<Void> bizResponse = new BizResponse<>();
        bizResponse.setCode(1000);
        bizResponse.setMsg(defaultMessage);
        return bizResponse;

    }

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Object requestExceptionHandle(HttpServletRequest req, HttpServletResponse response, Exception e) {
        log.error("requestExceptionHandle:{}", e.getMessage());
        log.error(getTrace(e));
        // print(response, BizRetStatus.ERROR.getCode(), new BizResponse<>(BizRetStatus.ERROR, StringUtils.isEmpty(e.getMessage()) ? "发生未知错误!" : e.getMessage()));
        return new BizResponse<>(BizRetStatus.ERROR, StringUtils.isEmpty(e.getMessage()) ? "发生未知错误!" : e.getMessage());
    }

    private String getTrace(Throwable t) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        t.printStackTrace(writer);
        StringBuffer buffer = stringWriter.getBuffer();
        return buffer.toString();
    }

    private void print(HttpServletResponse response, int code, Object obj) {
        try {
            response.setStatus(code);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setHeader("Cache-Control", "no-cache, must-revalidate");
            PrintWriter writer = response.getWriter();

            ObjectMapper mapper = new ObjectMapper();
            writer.write(mapper.writeValueAsString(obj));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            log.error("print response error, the detail is: ", e);
        }

    }
}
